#include <string>
#include <iostream>
#include <assert.h>
#include "../sequence/common.h"
#include "../sequence/MatrixTests.h"
#include "../sequence/Matrix.h"
#include "../sequence/RecurrenceOperator.h"
#include "../sequence/MatrixGenerator.h"
#include "../sequence/ResultStorage.h"
#include "../sequence/AlgebraFactory.h"


namespace testMatrix
{

template<int size>
void simmetryTest(const Matrix<size> &a, const Matrix<size> &b)
{
	assert((a == b) == (b == a));
}

template<int size>
void reflectTest(const Matrix<size> &a)
{
	assert(a == a);
}

template<int size>
void copyTest(const Matrix<size> &m)
{
	Matrix<size> _m(m);
	assert(m == _m);
}

template<int size>
void multTest(
	const IAlgebra &algebra,
	const typename MatrixOperator<size>::ControlSequence &c,
	const typename MatrixOperator<size>::Factorset &f,
	const Matrix<size> &M,
	const Matrix<size> &result)
{
	Matrix<size> _m(M);
	MatrixOperator<size, 2, left_operator_tag> rop(&algebra, c, f);
	rop.applyTo(&_m);
	assert(result == _m);

}

void test0()
{
	Matrix<> a;
	a.set(0, 0, 1);
	a.set(0, 1, 234);
	a.set(1, 0, 453);
	a.set(1, 1, 98);
	Matrix<> b;
	b.set(0, 0, 1);
	b.set(0, 1, 234);
	b.set(1, 0, 453);
	b.set(1, 1, 98);
	assert(a == b);
	simmetryTest(a, b);
	copyTest(a);
	copyTest(b);
	reflectTest(a);
	reflectTest(b);
	b.set(0, 0, 11);
	assert(!(a == b));
	simmetryTest(a, b);

	Matrix<3> a3;
	a3.set(0, 0, 1);
	a3.set(0, 1, 234);
	a3.set(0, 2, 23);
	a3.set(1, 0, 53);
	a3.set(1, 1, 4);
	a3.set(1, 2, 7);
	a3.set(2, 0, 98);
	a3.set(2, 1, 5);
	a3.set(2, 2, 9);
	Matrix<3> b3;
	b3.set(0, 0, 1);
	b3.set(0, 1, 234);
	b3.set(0, 2, 23);
	b3.set(1, 0, 53);
	b3.set(1, 1, 4);
	b3.set(1, 2, 7);
	b3.set(2, 0, 98);
	b3.set(2, 1, 5);
	b3.set(2, 2, 9);
	assert(a3 == b3);
	simmetryTest(a3, b3);
	copyTest(a3);
	copyTest(b3);
	reflectTest(a3);
	reflectTest(b3);
	b3.set(0, 0, 11);
	assert(!(a3 == b3));
	simmetryTest(a3, b3);
}

void test1()
{
	RingZ256 algebra;

	MatrixOperator<2, 2, left_operator_tag>::ControlSequence c;
	c.at(0) = 2;
	c.at(1) = 1;
	c.at(2) = 0;

	Matrix<> M;
	M.set(0, 0, 1);
	M.set(0, 1, 2);
	M.set(1, 0, 3);
	M.set(1, 1, 4);
	MatrixOperator<2, 2, left_operator_tag>::Factorset f;
	f.at(0) = algebra.unityElement();
	f.at(1) = algebra.unityElement();
	Matrix<> R;
	R.set(0, 0, 3);
	R.set(0, 1, 4);
	R.set(1, 0, 4);
	R.set(1, 1, 6);
	multTest(algebra, c, f, M, R);

	c.at(0) = 3;
	c.at(1) = 1;
	c.at(2) = 0;
	Matrix<3> a;
	for(int i = 0; i < 9; i++)
	{
		a.set(i / 3, i % 3, i + 1);
	}
	Matrix<3> R3;
	for(int i = 0; i < 6; i++)
	{
		R3.set(i / 3, i % 3, i + 4);
	}
	R3.set(2, 0, 5);
	R3.set(2, 1, 7);
	R3.set(2, 2, 9);
	multTest(algebra, c, f, a, R3);
}

void runtests()
{
	test0();
	test1();
}

}
